#include <vector>
#include <iostream>
using namespace std;
#include "meta/type_list.h"
#include "meta/type_traits.h"
using namespace tdl;

class CA
{
public:
	CA() : i(1) {}
	int i;
};
class CB : public CA
{
public:
	CB() : s("abc") {}
	string s;
};
class CC {};

template <typename T>
class cache
{
public:
	T m;
};

//////////////////////
int main(int argc, char *argv[])
{
	// test for btypes
	cout << "===== test for base_types =====" << endl;
	cout << "CA is CA: " << is_same_type<CA, CA>::value << endl;
	cout << "CA is CB: " << is_same_type<CA, CB>::value << endl;
	cout << "CB is CA: " << is_same_type<CB, CA>::value << endl;
	
	cout << "CB->CA=" << is_super_sub_class<CA, CB>::value << "\t"
		 << "CA->CB=" << is_super_sub_class<CB, CA>::value << "\t"
		 << "CC->CA=" << is_super_sub_class<CA, CC>::value << "\t"
 		 << "CA->CC=" << is_super_sub_class<CC, CA>::value << "\t"
		 << endl;

	cout << "null_type = null_type: " << is_same_type<null_type, null_type>::value << endl;
	cout << "null_type = empty_type: " << is_same_type<null_type, empty_type>::value << endl;
	cout << "empty_type = empty_type: " << is_same_type<empty_type, empty_type>::value << endl;
	cout << "empty_type = null_type: " << is_same_type<empty_type, null_type>::value << endl;

	// test for type_list
	cout << "===== test for tlop =====" << endl;
	typedef make_type_list<char, short, int, long>::type mytl;
	
	cout << "length of typelist=" << tlop::length<mytl>::value << endl;
	cout << "3rd type is int: " << is_same_type<tlop::at<mytl, 2>::type, int>::value << endl;
	cout << "6th type is null_type: " << is_same_type<tlop::at<mytl, 5>::type, null_type>::value << endl;
	cout << "6th type is empty_type: " << is_same_type<tlop::at<mytl, 5, empty_type>::type, empty_type>::value << endl;
	cout << "at<mytl, -1, int> is int: " << is_same_type<tlop::at<mytl, -1, int>::type, int>::value << endl;
	cout << "int type index=" << tlop::index<mytl, int>::value << endl;
	cout << "float type index=" << tlop::index<mytl, float>::value << endl;
	cout << "after appending length=" << tlop::length<tlop::append<mytl, mytl>::type>::value << endl;
	cout << "int index after removing=" << tlop::index<tlop::remove<mytl, int>::type, int>::value << endl;
	cout << "float index after replacing int=" << tlop::index<tlop::replace<mytl, int, float>::type, float>::value << endl;
	typedef tlop::right<mytl, 2>::type rttl;
	cout << "length<right<mytl, 2> >=" << tlop::length<rttl>::value << endl;
	cout << "index<rttl, long>=" << tlop::index<rttl, long>::value << endl;
	cout << "right<mytl, 6> is null_type: " << is_same_type<tlop::right<mytl, 6>::type, null_type>::value << endl;
	
	typedef make_type_list<CA, CB, CB, CA, CC>::type duptl;
	cout << "after unique length=" << tlop::length<tlop::unique<duptl>::type>::value << endl;
	cout << "after remove_all CB, length=" << tlop::length<tlop::remove_all<duptl, CB>::type>::value
		 << ", CC index=" << tlop::index<tlop::remove_all<duptl, CB>::type, CC>::value << endl;

	// test for type_traits
	cout << "===== test for type_traits =====" << endl;
	cout << "char* is void*: " << is_same_type<char*, void*>::value << endl;
	cout << "traits<char*>::pointee_type is char: " << is_same_type<char, type_traits<char*>::pointee_type>::value << endl;
	cout << "traits<char*>::is_pointer: " << type_traits<char*>::is_pointer << endl;
	cout << "tratis<int>::is_pointer: " << type_traits<int>::is_pointer << endl;
	cout << "traits<vector<int>::iterator>::is_pointer: " << type_traits<vector<int>::iterator>::is_pointer << endl;
	cout << "traits<CB&>::is_reference: " << type_traits<CB&>::is_reference << endl;
	cout << "traits<CB*>::is_reference: " << type_traits<CB*>::is_reference << endl;
	cout << "tratis<int>::is_const: " << type_traits<int>::is_const << endl;
	cout << "traits<const CC>::is_const: " << type_traits<const CC>::is_const << endl;
	cout << "traits<const int*>::deconst_type is int*: " << is_same_type<type_traits<const int*>::deconst_type, int*>::value << endl;
	cout << "traits<const int*>::org_type is int: " << is_same_type<type_traits<const int*>::org_type, int>::value << endl;
	cout << "traits<int>::is_stdint=" << type_traits<int>::is_stdint << endl;
	cout << "traits<CB>::param_type is CB&: " << is_same_type<type_traits<CB>::param_type, CB&>::value << endl;
	cout << "traits<CB&>::param_type is CB&: " << is_same_type<type_traits<CB&>::param_type, CB&>::value << endl;
	cout << "traits<CB>::const_param_type is const CB&: " << is_same_type<type_traits<CB>::const_param_type, const CB&>::value << endl;

	// test for make_type_list_by
	typedef tlop::make_type_list_by<cache, mytl>::type nouse_type;

	return 0;
}

